package DataReading;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.Scanner;

// This class will load the file and manage operations for VMS - CLASS NAME IS PROGRESS
public class LoadSystem {
	
	// Variables for class
	private String fileName;
	private SystemInfo info;
	private VesselList vessels; // Idle list where ships haven't started yet
	private VesselList currentVessels; // List of Ships that are being displayed
	private AlarmList alarms;
	private double currentTime;
	private double previousTime;
	private int sortKey = 0;
	private int orderKey = 0;
	
	// Class Constructor which handles the operations up to loading the file and reading data in classes
	public LoadSystem(String fn) throws FileNotFoundException {
		this.fileName = fn;
		vessels = new VesselList(5);
		info = new SystemInfo();
		readContents();
		currentTime = info.getStartTime();
		intializeVessels();
	}
	
	// Mutatorss for class, Info & Vessals Mutator need not be given, as they are loaded with file.
	public void setFileName(String fn) { this.fileName = fn; }
	
	// Accessors for the Class
	public String getFileName() { return this.fileName; }	
	public SystemInfo getInfo() { return this.info; }
	public VesselList getVessels() { return this.vessels; }
	public VesselList getCurrentVessels() { return this.currentVessels; }
	public AlarmList getAlarms() { return this.alarms; }
	public int getSortKey() { return this.sortKey; }
	public int getOrderKey() { return this.orderKey; }
	
	public void setSortKey(int key) { sortKey = key; }
	public void setOrderKey(int key) { orderKey = key; }
	
	
	// Method to update the positions of every vessel on a interval. Parameter time is passed as time of update required
	public void updateVessalPositions(double time) {
		System.out.println(time);
		previousTime = currentTime;
		currentTime = time;
		alarms = new AlarmList();
		
		// Loops through the vessels in the idle vessel list and adds them to current vessels if its time for their start
		for (int i = 0; i <= vessels.getPointer(); i++) {
			Vessel v = vessels.getVesselAtIndex(i);
			if (v != null && v.getStartTime() > previousTime && v.getStartTime() <= currentTime) {
				currentVessels.add(vessels.getVesselAtIndex(i)); // Adds to the current vessels
				//vessels.remove(i); // removed from the idle vessel list
			}
		}	
		
		// Loop through the current vessels and update the positions according to time and removes if they out of range
		for(int i = 0; i < currentVessels.getPointer(); i++) { 
			Vessel v = currentVessels.getVesselAtIndex(i);
			if (v != null) {
				double newXPosition = v.getInitXP() + (v.getXVelocity() * (currentTime - v.getStartTime()));
				double newYPosition = v.getInitYP() + (v.getYVelocity() * (currentTime - v.getStartTime()));
				if (Math.abs(newXPosition) <= info.getRange() && Math.abs(newYPosition) <= info.getRange()) {
					v.setXPosition(newXPosition);
					v.setYPosition(newYPosition);
					v.updateCourse();
					v.updateDistance();
					v.timeUpdate(currentTime);
				}
				else {
					currentVessels.remove(i);
				}
			}
		}
		// Find distances between vessels and set the alarms
		for(int i = 0; i < currentVessels.getPointer(); i++) { 
			for(int j = i+1; j < currentVessels.getPointer(); j++) {
				calculateAlarm(currentVessels.getVesselAtIndex(i), currentVessels.getVesselAtIndex(j));
			}
		}
		
		//sortVessels();
		currentVessels = Tools.sortVessels(currentVessels, sortKey, orderKey);
	}
	
	public void calculateAlarm(Vessel x, Vessel y) {
		// Gonna Use pythagore's algorithm to calculate distance
		double a = Math.abs(x.getXPosition() - y.getXPosition());
		double b = Math.abs(x.getYPosition() - y.getYPosition());
		a = a * a;
		b = b * b;
		double c = Math.sqrt(a + b);
		if (c <= 200) {
			Alarm m = new Alarm (x,y,c);
			alarms.add(m);
		}
	}
	
	public void intializeVessels() {
		currentVessels = new VesselList(vessels.getPointer()+1);
		alarms = new AlarmList();
		for(int i = 0; i < vessels.getPointer(); i++) {
			if (vessels.getVesselAtIndex(i).getStartTime() == 0) {
				currentVessels.add(vessels.getVesselAtIndex(i));
				//vessels.setVesselAtIndex(null, i);
			}
		}
	}
	
	public void sortVessels() {
		for(int i = 0; i < currentVessels.getPointer()-1; i++) { 
			//int min = i;
			for(int j = i; j < currentVessels.getPointer(); j++) {
				if (currentVessels.getVesselAtIndex(j).getID() < currentVessels.getVesselAtIndex(i).getID()) {
					//min = j;
					Vessel temp = currentVessels.getVesselAtIndex(j);
					currentVessels.setVesselAtIndex(currentVessels.getVesselAtIndex(i), j);
					currentVessels.setVesselAtIndex(temp, i);	
				}
			}
			//if (min != i) {
//			Vessel temp = currentVessels.getVesselAtIndex(min);
//			currentVessels.setVesselAtIndex(currentVessels.getVesselAtIndex(i), min);
//			currentVessels.setVesselAtIndex(temp, i);					
			//}
		}
	}
	// Method to read in the contents of the vsf file
	public void readContents() throws FileNotFoundException {
		
		Scanner readFile = new Scanner(new FileInputStream(fileName));
			
			// This will only get the information required and skip all comments.
			while (readFile.hasNextLine()) { 
				String next = readFile.next();
				if (next.equals("VSF")) { 
					info.setVersion(readFile.nextInt());
				}
				else if (next.equals("STARTTIME")) {
					info.setStartTime(readFile.nextInt());
				}
				else if (next.equals("TIMESTEP")) {
					info.setTimeStep(readFile.nextInt());	
				}
				else if (next.equals("TIME")) {
					info.setTime(readFile.nextInt());				
				}
				else if (next.equals("RANGE")) {
					info.setRange(readFile.nextInt());;				
				}
				else if (next.equals("NEWT")) {
					// Every vessal is created here and added to the Vessel List
					int id = readFile.nextInt();
					int type = readFile.nextInt();
					double xp = readFile.nextDouble();
					double yp = readFile.nextDouble();
					double xv = readFile.nextDouble();
					double yv = readFile.nextDouble();
					int startTime = readFile.nextInt();
					
					Vessel temp = new Vessel(id, type, xp, yp, xv, yv, startTime);
					double a = temp.getXVelocity();
					double b = temp.getYVelocity();
					temp.setSpeed(Math.sqrt(a + b));
					vessels.add(temp);
					temp = null;				
				}
				if(readFile.hasNextLine()) {
					readFile.nextLine();
				}
			
		}
			readFile.close(); // Close File
	}
	
	
// These methods are only used to test the data/alarm being updated and outputing	

	public String displayTable() {
		String[][] table = getTableContents();
		String[][] alarmTable = getAlarmTable();
		
		String output = "ID \t Type \t StarTime \t XPos \t YPos \t XVel \t Yvel \n";
		
		for (int i = 0; i < table.length; i++) {
			for (int j = 0; j < table[0].length; j ++) {
				output += table[i][j] + " \t";
			}
			output += "\n";
		}
		output += "\n";
		for (int i = 0; i < alarmTable.length; i++) {
			for (int j = 0; j < alarmTable[0].length; j ++) {
				output += alarmTable[i][j] + " \t";
			}
			output += "\n";
		}
		
		return output;
	}
	
	public String[][] getTableContents() {
		String [][] table = new String[currentVessels.getPointer()][7];
		for (int i = 0; i < currentVessels.getPointer(); i++) {
			Vessel v = currentVessels.getVesselAtIndex(i);
			if (v != null) {
				table[i][0] = "" + v.getID();
				table[i][1] = v.getTypeName();
				table[i][2] = "" + v.getStartTime();
				table[i][3] = "" + v.getXPosition();
				table[i][4] = "" + v.getYPosition();
				table[i][5] = "" + v.getXVelocity();
				table[i][6] = "" + v.getYVelocity();
			}
		}
		return table;
	}
	
	public String[][] getAlarmTable() {
		String [][] table = new String[alarms.getPointer()][6];
		for (int i = 0; i < alarms.getPointer(); i++) {
			Alarm a = alarms.getAlarmAtIndex(i);
			if (a != null) {
				table[i][0] = "" + a.getVesselX().getID();
				table[i][1] = a.getVesselX().getTypeName();
				table[i][2] = "" + a.getVesselY().getID();
				table[i][3] = a.getVesselY().getTypeName();
				table[i][4] = "" + a.getDistance();
				table[i][5] = "" + a.getAlarmType();
			}
		}
		return table;
	}
	
}
